#![feature(convert_float_to_int)]
mod db;
mod aliyun;

use std::path::PathBuf;
use std::process::Command;

use clap::Parser;
use db::Catalog;
use mysql::Pool;

use async_recursion::async_recursion;

#[derive(Debug, Parser, Clone)]
#[clap(name = "StatsVideoDuration", bin_name = "stats-video-duration", long_about = "统计mrms中oss的视频时长")]
#[clap(author, version, about="统计mrms中oss的视频时长", long_about = None)]
struct App {
    #[clap(value_parser, help="数据库链接")]
    mysql_url: Option<String>,
    #[clap(value_parser, help="阿里云AccessKeyId")]
    aliyun_access_key_id: Option<String>,
    #[clap(value_parser, help="阿里云AccessKeySecret")]
    aliyun_access_key_secret: Option<String>,
    #[clap(value_parser, help="阿里云Endpoint")]
    aliyun_endpoint: Option<String>,
    #[clap(value_parser, help = "输出文件路径")]
    output: PathBuf,
}

#[derive(Debug, thiserror::Error)]
enum Error {
    #[error("执行命令失败：{0}")]
    Command(String),
}

fn get_video_duration(video_path: String) -> anyhow::Result<u64> {
    match Command::new("ffprobe")
        .arg("-v")
        .arg("error")
        .arg("-show_entries")
        .arg("format=duration")
        .arg("-of")
        .arg("default=noprint_wrappers=1:nokey=1")
        .arg(video_path)
        .output()
    {
        Ok(o) => {
            if !o.status.success() {
                return Err(anyhow::anyhow!(Error::Command(
                    String::from_utf8(o.stderr).unwrap()
                )));
            }
            match String::from_utf8(o.stdout) {
                Ok(s) => match s.trim().parse::<f64>() {
                    Ok(r) => Ok(unsafe { r.to_int_unchecked() }),
                    Err(e) => Err(anyhow::anyhow!(Error::Command(e.to_string()))),
                },
                Err(e) => Err(anyhow::anyhow!(Error::Command(e.to_string()))),
            }
        }
        Err(e) => Err(anyhow::anyhow!(Error::Command(e.to_string()))),
    }
}

#[derive(Debug)]
struct VideoRecord {
    catalog: String,
    name: String,
    duration: f64,
}

#[async_recursion]
async fn stats_video_duration(catalog_id: i64, paths: Vec<String>, app: App) -> anyhow::Result<Vec<VideoRecord>> {
    let pool = Pool::new("mysql://root:123456@localhost:3306/mrms")?;
    let mut conn = pool.get_conn()?;
    let catalogs = db::get_catalogs(catalog_id, &mut conn);
    let mut records: Vec<VideoRecord> = vec![];
    let client = aliyun::AliyunClient::new(
        "LTAI14o1sxqlxCYM".to_string(), 
        "Tyf9Px66L4N3oFqL883y8Jrrba3K9T".to_string(), 
        "https://vod.cn-shanghai.aliyuncs.com".to_string()
    );
    for Catalog {catalog_id, catalog_name} in catalogs {
        let videos = db::get_files(catalog_id, &mut conn);

        for v in videos {
            let mut video_catalog_paths = paths.clone(); 
            video_catalog_paths.push(format!("{}({})", catalog_name, capplog_id));
            let video_catalog_path = video_catalog_paths.join("/");
            let response = client.clone().get_video_info(v.aliyun_vid).await?;
            let duration = response.video.duration;
            records.push(VideoRecord {
                catalog: video_catalog_path,
                name: v.file_alias,
                duration,
            });
        }
        let mut new_paths = paths.clone();
        new_paths.push(catalog_name);
        let next_rows = stats_video_duration(catalog_id, new_paths).await?;
        records.extend(next_rows);
    }

    Ok(records)
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    env_logger::init();
    let records = stats_video_du8ration(8918, vec![]).await?;
    let mut writer = csv::Writer::from_path("result.csv")?;
    writer.write_record(["目录", "视频名", "时长"])?;
    for r in records {
        writer.write_record([r.catalog, r.name, r.duration.to_string()])?;
    }
    Ok(())
}
